/**
 *  Copyright (C) 2006 zhangbo (freeeob@gmail.com)
 *
 *  This product is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 * 
 *  This product is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 *
 *  author:zhangbo
 *  Email:jsjava@gmail.com
 */

/**  The Complex class references to org.apache.commons.math.complex.Complex */

function Complex(real,imaginary){
	this.jsjava_class="org.apache.commons.math.complex.Complex";
	this.real=real;
	this.imaginary=imaginary;
}

/*** The square root of -1. A number representing "0.0 + 1.0i" */
Complex.I = new Complex(0.0, 1.0);
    
/*** A complex number representing "NaN + NaNi" */
Complex.NaN = new Complex(Double.NaN, Double.NaN);

/*** A complex number representing "1.0 + 0.0i" */    
Complex.ONE = new Complex(1.0, 0.0);

/*** A complex number representing "0.0 + 0.0i" */    
Complex.ZERO = new Complex(0.0, 0.0);

/**
 * Return the absolute value of this complex number.
 */
Complex.prototype.abs=function(){
	if (this.isNaN()) {
        return Double.NaN;
    }
    
    if (this.isInfinite()) {
        return Double.POSITIVE_INFINITY;
    }
    var real=this.real;
    var imaginary=this.imaginary;
    if (Math.abs(real) < Math.abs(imaginary)) {
        if (imaginary == 0.0) {
            return Math.abs(real);
        }
        var q = real / imaginary;
        return (Math.abs(imaginary) * Math.sqrt(1 + q*q));
    } else {
        if (real == 0.0) {
            return Math.abs(imaginary);
        }
        var q = imaginary / real;
        return (Math.abs(real) * Math.sqrt(1 + q*q));
    }
};

/**
 * Return the sum of this complex number and the given complex number.
 * @param rsh the other complex number 
 */
Complex.prototype.add=function(rhs){
	return new Complex(this.real + rhs.getReal(),this.imaginary + rhs.getImaginary());
};

/**
 * the conjugate of this Complex object
 */
Complex.prototype.conjugate=function(){
	if (this.isNaN()) {
        return Complex.NaN;
    }   
    return new Complex(this.real, -this.imaginary);
};

/**
 * Return the quotient of this complex number and the given complex number. 
 * @param rhs the other complex number 
 */
Complex.prototype.divide=function(rhs){
	if (this.isNaN() || rhs.isNaN()) {
        return Complext.NaN;
    }
    var real=this.real;
    var imaginary=this.imaginary;
    var c = rhs.getReal();
    var d = rhs.getImaginary();
    if (c == 0.0 && d == 0.0) {
        return Complex.NaN;
    }
    
    if (rhs.isInfinite() && !this.isInfinite()) {
        return Complex.ZERO;
    }

    if (Math.abs(c) < Math.abs(d)) {
        if (d == 0.0) {
            return new Complex(real/c, imaginary/c);
        }
        var q = c / d;
        var denominator = c * q + d;
        return new Complex((real * q + imaginary) / denominator,(imaginary * q - real) / denominator);
    } else {
        if (c == 0.0) {
            return new Complex(imaginary/d, -real/c);
        }
        var q = d / c;
        var denominator = d * q + c;
        return new Complex((imaginary * q + real) / denominator,(imaginary - real * q) / denominator);
    }
};

/**
 * Test for the equality of two Complex objects.
 * @param o
 */
Complex.prototype.equals=function(o){
	if(o==undefined){
        return false; 
    }
    if(o.jsjava_class&&o.jsjava_class=="org.apache.commons.math.complex.Complex"){
        return this.real==o.real&&this.imaginary==o.imaginary;
    }
    return false;
};

/**
 * Access the imaginary part. 
 */
Complex.prototype.getImaginary=function(){
	return this.imaginary;
};

/**
 * Access the real part. 
 */
Complex.prototype.getReal=function(){
	return this.real;
};

/**
 * Access the real part.
 */
Complex.prototype.isInfinite=function(){
	return !this.isNaN() && (Double.isInfinite(this.real) || Double.isInfinite(this.imaginary));   
};

/**
 * Returns true if either or both parts of this complex number is NaN; false otherwise
 */
Complex.prototype.isNaN=function(){
	return Double.isNaN(this.real) || Double.isNaN(this.imaginary); 
};

/**
 * Return the product of this complex number and the given complex number. 
 * @param rhs the other complex number 
 */
Complex.prototype.multiply=function(rhs){
	if (this.isNaN() || rhs.isNaN()) {
        return Complex.NaN;
    }
    return new Complex(this.real * rhs.real - this.imaginary * rhs.imaginary,
            this.real * rhs.imaginary + this.imaginary * rhs.real);
};

/**
 * Return the additive inverse of this complex number. 
 */
Complex.prototype.negate=function(){
	if (this.isNaN()) {
        return Complex.NaN;
    }    
    return new Complex(-this.real, -this.imaginary);
};

/**
 * Return the difference between this complex number and the given complex number. 
 * @param rhs the other complex number 
 */
Complex.prototype.subtract=function(rhs){
	if (this.isNaN() || rhs.isNaN()) {
        return Complex.NaN;
    }
    
    return new Complex(this.real - rhs.getReal(),
        this.imaginary - rhs.getImaginary());
};

/**
 * return a string description
 */
Complex.prototype.toString=function(){
	var str=this.real;
	if(this.imaginary>=0){
		str+="+";
	}
	str+=this.imaginary+"i";
	return str;
};